using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;

// this is the "always true" warning
#pragma warning disable 183

namespace LINQ.Prep
{
   [TestFixture]
   public class FullPresentation
   {
      // Condensed presentation here

      [Test]
      public void Demo3_getting_interesting__agendas_grouped_by_year()
      {
         // review the AMS data model

         /* story:
          * I want a list of agendas by year for a particular location
          * starting with the most current year. 
          */

         using (var entities = new AMSDataContext())
         {
            // force query - we're here to talk about LINQ, not LINQ to SQL
            Agenda[] agendas = entities.Agendas.Where(x => x.LocationId == 1).ToArray();

            IEnumerable<IEnumerable<Agenda>> agendasByYear =
               agendas
                  .GroupBy(x => x.Date.Year)
                  .OrderByDescending(x => x.Key)
                  .Select(x => (IEnumerable<Agenda>)x);

            Assert.IsTrue(agendasByYear.Count() > 0);
            Assert.IsTrue(agendasByYear.All(x => x is IEnumerable<Agenda>));
            Assert.IsTrue(agendasByYear.All(x => x.Select(agenda => agenda.Date.Year).Distinct().Count() == 1));
         }
      }

      [Test]
      public void Demo4_comparing_voters()
      {
         /* story:
          * I know voter 'X' and want to know voter 'Y'.  I want to do this by comparing the things they
          * voted on.  Specifically, I want to see where their votes were not the same.
          * While we're at it, let me compare any number of voters at the same time!
          */
         using (var entities = new AMSDataContext())
         {
            var voters = new[] {"Core", "Watson"};

            IQueryable<AgendaItem> baseQuery = entities.AgendaItems.Where(x => x.Agenda.LocationId == 1);

            IOrderedEnumerable<int> agendaItemIds_AG =
               (from item in baseQuery
                from itemVote in item.AgendaItemVotes
                where voters.Contains(itemVote.AgendaVoter.Voter.DisplayName)
                group itemVote by itemVote.AgendaItemId
                into votes
                   from vote in votes
                   where votes.Count() == voters.Length
                   where !votes.Any(x => x.Vote == "Absent")
                   group vote by new {vote.AgendaItemId, vote.Vote}
                into g
                   where g.Count() < voters.Length
                   select g.Key.AgendaItemId).Distinct().ToArray().OrderBy(x => x);

            IOrderedEnumerable<int> agendaItemIds =
               baseQuery
                  .SelectMany(item => item.AgendaItemVotes)
                  .Where(agendaItemVote => voters.Contains(agendaItemVote.AgendaVoter.Voter.DisplayName))

                  .GroupBy(agendaItemVote => agendaItemVote.AgendaItemId)
                  .Where(grouping => grouping.Count() == voters.Length)
                  .Where(grouping => !grouping.Any(agendaItemVote => agendaItemVote.Vote == "Absent"))

                  .SelectMany(grouping => grouping)
                  .GroupBy(agendaItemVote => new {agendaItemVote.AgendaItemId, agendaItemVote.Vote})
                  .Where(grouping => grouping.Count() < voters.Length)

                  .Select(grouping => grouping.Key.AgendaItemId)
                  .Distinct()
                  .ToArray()
                  .OrderBy(x => x);

            Assert.AreEqual(agendaItemIds_AG.Count(), agendaItemIds.Count());

            baseQuery = baseQuery.Where(x => agendaItemIds.Contains(x.Id));
            Assert.IsTrue(baseQuery.Count() > 0);
         }
      }
   }
}

#pragma warning restore 183